/***************************************************************************
 *   Copyright (C) 2008 by Eduardo Gurgel Pinho                            *
 *   edgurgel@gmail.com                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
***************************************************************************/

#include "square_light.h"

#include "common/random_generator.h"
#include "math/ray.h"
#include "material/light_material.h"

namespace Sirat {

namespace Light {

Square_Light::Square_Light(Material::Light_Material* const _light_material,const Math::Vector& _point0,const Math::Vector& _point1,const Math::Vector& _point2,const Math::Vector& _point3) : Light(_light_material) { 
	points[0] = _point0;
	points[1] = _point1;
	points[2] = _point2;
	points[3] = _point3;
} 

Square_Light::Square_Light() { 
	points[0] = Math::Vector(-1.0,0.0,0.0);
	points[1] = Math::Vector(1.0,0.0,0.0);
	points[2] = Math::Vector(1.0,1.0,0.0);
	points[3] = Math::Vector(-1.0,1.0,0.0);
} 

Square_Light::Square_Light(const Square_Light& _square_light) : Light(_square_light) {
	points[0] = _square_light.points[0];
	points[1] = _square_light.points[1];
	points[2] = _square_light.points[2];
	points[3] = _square_light.points[3];
}

Square_Light::~Square_Light() { }

Math::Vector Square_Light::get_point(unsigned short& _index) const {
	return points[_index];
}

void Square_Light::set_point(const Math::Vector& _point,unsigned short& _index) {
	points[_index] = _point;
}

tuple<Math::Vector*,unsigned int> Square_Light::get_sample_points() const {
	Math::Vector* sample_points = new Math::Vector[4];
	for(unsigned short i = 0;i < 4; i++) sample_points[i] = points[i];
	
	return make_tuple(sample_points,4);
}

tuple<Math::Vector*,unsigned int> Square_Light::get_sample_points(const Common::Random_Generator& _random_generator,const unsigned int _n) const {
	Math::Vector* sample_points = new Math::Vector[_n];
	for(unsigned short i = 0;i < _n; i++) {
		double u = (_random_generator.generate() +1.0)/2.0;
		double v = (_random_generator.generate() +1.0)/2.0;
		sample_points[i] = points[0]*(1.0-u)*(1.0 -v) + points[1]*(1.0-u)*v + points[2]*u*v + points[3]*u*(1.0-v);
	}
	return make_tuple(sample_points,_n);
}

Math::Ray* Square_Light::get_sample_directions(const Common::Random_Generator& _random_generator,const unsigned int _n) const {
	Math::Ray* sample_directions = new Math::Ray[_n];
	Math::Vector* sample_points = get_sample_points(_random_generator,_n).get<0>();
	for(unsigned int i = 0; i < _n; i++) {
		Math::Vector direction;
		do {
			direction = Math::Vector(_random_generator.generate(),_random_generator.generate(),_random_generator.generate());
		} while(direction.length() > 1.0);
		direction = direction.normalize();
		Math::Ray ray(sample_points[i],direction);
		sample_directions[i] = ray;
	}
	delete sample_points;
	return sample_directions;	
}

Square_Light& Square_Light::operator=(const Square_Light& _square_light) {
	Light::operator=(_square_light);
	points[0] = _square_light.points[0];
	points[1] = _square_light.points[1];
	points[2] = _square_light.points[2];
	points[3] = _square_light.points[3];
	return *this;	
}

Light* Square_Light::clone() {
	return new Square_Light(*this);
}

}

}
